home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / std / c++ / 852 < prev    next >
Encoding:
Internet Message Format  |  1996-08-06  |  6.2 KB

  1. Path: cs.mu.OZ.AU!bounce-back
  2. From: Rob Stewart <stew@datalytics.com>
  3. Newsgroups: comp.std.c++
  4. Subject: Re: constness of private members and methods
  5. Date: 26 Mar 96 06:55:16 GMT
  6. Organization: Datalytics, Inc
  7. Approved: fjh@cs.mu.oz.au
  8. Message-ID: <31570972.3230@datalytics.com>
  9. References: <4j49e0$8fo@dub-news-svc-4.compuserve.com>
  10. NNTP-Posting-Host: munta.cs.mu.oz.au
  11. X-Original-Date: Mon, 25 Mar 1996 16:00:34 -0500
  12. X-Mailer: Mozilla 2.0 (WinNT; I)
  13. X-Auth: PGPMoose V1.1 PGP comp.std.c++
  14.     iQBFAgUBMVeU/uEDnX0m9pzZAQFByAF/cSlCWypHS7yTkSXLfkHF3qZkQhxou8oc
  15.     owytKt9kwyq8JYQK3Hb4SD2GYcEM8WXz
  16.     =O63S
  17. Originator: fjh@munta.cs.mu.OZ.AU
  18.  
  19. Philippe Verdy wrote:
  20. > Many recursive data structures require algorithms to handle
  21. > them which have to mark and unmark all scanned objects in
  22. > order to avoid infinite recursion when walking on that
  23. > structure, or when building items iterator.
  24. > Such algorithms will use the mark() and unmark() private
  25. > methods in each visited node, so that we can detect paths
  26. > which have already been visited. his is critical for example
  27. > when managing with auto-references, graphs, dictionnaries
  28. > of polymorphic objects (containing dictionnaries like in
  29. > a PostScript interpret).
  30. > However, how can we apply standard read-only methods on such
  31. > objects: these methods are specified as const in one of the
  32. > base classes, and virtual override requires not to change the
  33. > constness of the derived object.
  34. > So we cannot mark such structures, because even a private
  35. > member cannot be modified in a const instance.
  36. > We can effectively change temporarily the constness of the
  37. > object to realize this mark, but in that case we would write
  38. > the following :[snip]
  39. > The problem is that now mark() and unmark() methods are not
  40. > const so they cannot be used in read-only methods like show().
  41. > So we have to use a const_cast<T&> or const_cast<T*> to
  42. > suppress this constness.
  43. > This is not obvious, and has the big disadvantage of globally
  44. > suppressing the constness of the object. So this is quite
  45. > dangerous, because some-times, we do not know really if a
  46. > method has an impact on the semantic value of the instance
  47. > on which we apply this cast. So this is a security hole which
  48. > should be avoided.
  49. > We can avoid const_casting to call mark() and unmark() by
  50. > declaring them as const, like this:[snip]
  51. > but this is really hard to write, and is it semantically
  52. > correct ? It would from the public point of view, but what
  53. > on the private point of view ?
  54. > We can also use explicitly (const_cast<T*>this)->mark(); and
  55. > (const_cast<T*>this)->unmark(); calls in the show()
  56. > implementation, but this is quite hard to write, so that many
  57. > users refrain using const specifiers on their classes.
  58. > [snip]
  59. > What do you think ?
  60. > And is constness definition a semantic only definition,
  61. > or does it involve a more strict sense in which the compiler
  62. > optimizer would have an influence (such as in common
  63. > subexpressions reduction) ?
  64.  
  65. There are two schools of thought regarding const-ness.  One 
  66. requires strict bitwise constness.  That means that if you 
  67. construct a const object, did a memcpy of the object to some 
  68. suitable buffer, exercised the object using any permissible 
  69. (const) mfs, in any combination, then compared the object with 
  70. the memcpy'd buffer, there would be no change.
  71.  
  72. The other requires only logical constness.  That means that the 
  73. object always appears the same through its public and protected 
  74. interfaces.  You can do what you want inside the object, 
  75. provided it always appears the same to the class user.
  76.  
  77. The compiler obviously enforces the former definition.  You must 
  78. cast away constness when you want the latter.  That definition 
  79. is the one you're employing here.
  80.  
  81. According to how you've described mark and unmark, they must be 
  82. controlled by other functions such that the original state is 
  83. restored before return to the caller.  That is, some other 
  84. function must use mark and unmark, in matched sets for each 
  85. node, in order to preserve the external state of the object.  
  86.  
  87. Therefore, it is not mark and unmark which should cast away 
  88. constness, but those functions that make use of them.  mark and 
  89. unmark should be non-const; they each change the state in a way 
  90. that affects the external state of the class.  Those functions 
  91. calling them must cast away constness to use them.
  92.  
  93. As for your question about some language extension to permit 
  94. that behavior, it could only apply to functions calling mark and 
  95. unmark in their use of them.  That is, since only 
  96. functions using mark and unmark can ensure that the 
  97. original state is restored--thus preserving the logical 
  98. constness--only they can be used on const objects.  Therefore, 
  99. they should be the ones to get special dispensation to use 
  100. non-const mfs in such a way that they retain logical constness.
  101.  
  102. The difficulty is with maintenance.  Sure, after some design and 
  103. debugging work, you can get the functions to work correctly such 
  104. that you retain logical constness.  The maintainer of your code 
  105. may have more trouble or may not realize the consequence of his 
  106. actions, and destroy logical constness.  Once you violate the 
  107. bitwise constness of the compiler, you're on your own.  This is 
  108. true of casting away constness yourself, but would we really 
  109. want a language feature which makes it easy and makes less clear 
  110. where special attention is required?
  111.  
  112. I don't think so.  Instead, you should consider how to build a 
  113. base class that encapsulates the iteration process to which you 
  114. can pass a derived class mf to process each node you encounter.  
  115. The implementation will appear once in your code and shouldn't 
  116. require maintenance once you fix the bugs.  All the rest of your 
  117. code that needs to iterate the container will make use of that 
  118. base class functionality, but won't need to worry about casting 
  119. away constness.
  120.  
  121. -- 
  122. Robert Stewart        | My opinions are usually my own.
  123. Datalytics, Inc.    | stew@datalytics.com
  124. ---
  125. [ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
  126. [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
  127. [ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
  128. [ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
  129. [ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]
  130.